home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
HEAP_UTL
/
HDEB20S
/
LIESMICH.TXT
< prev
next >
Wrap
Text File
|
1995-04-17
|
54KB
|
1,099 lines
Der
HEAP DEBUGGER V2.0
für
BORLAND PASCAL V7.0
(DOS, DOS/DPMI, WINDOWS)
Copyright 1995
by
AIT GmbH
Alte Gasse 12 - 86152 Augsburg
Germany
Tel. +49 (821) 514868
Fax: +49 (821) 514831
FIDO-Net: Karsten Strobel @ 2:2480/300.7
Internet: kstrobel@gewi.muc.nacamar.de
INHALT
EINFÜHRUNG
Der Sinn des Heap Debuggers ......................................... 3
Was der Heap Debugger kann .......................................... 3
Was der Heap Debugger NICHT kann .................................... 3
Der Umgang mit dynamischem Speicher ................................. 3
Versionen und Zielplattformen ....................................... 4
Liste der Dateien ................................................... 5
Sharewarekonzept .................................................... 5
Lizenzbedingungen ................................................... 5
Nutzungsempfehlungen und Haftungsausschlüsse ........................ 6
ANWENDUNG DES HEAP DEBUGGERS
Den Heap Debugger einbinden ......................................... 6
Compiler- und Linkereinstellungen ................................... 7
Wenn die Initialisierung fehlschlägt ................................ 7
Der Heap Debugger Report ............................................ 8
Besondere Meldungen im Heap Debugger Report ......................... 9
Interpretation des Reports .......................................... 10
Auffinden von Bugs .................................................. 11
Arbeiten mit einem externen Debugger ................................ 11
Compilerschalter in USEHDEB ......................................... 12
HEAP DEBUGGING IM DETAIL
Overlays ............................................................ 13
DLLs ................................................................ 13
Programminstanzen (Windows) ......................................... 14
Interrupts .......................................................... 14
Stabilität und Performance .......................................... 14
Eingriffsmöglichkeiten für den Programmierer ........................ 15
BEKANNTE EINSCHRÄNKUNGEN UND PROBLEME
Mark/Release ........................................................ 16
MemAllocSeg ......................................................... 17
BGI ................................................................. 18
TMemoryStream ....................................................... 18
Heapüberlauf ........................................................ 18
Programmabbruch ..................................................... 19
WINCRT .............................................................. 19
Seite 3
EINFÜHRUNG _____________________________________________________________
___ Der Sinn des Heap Debuggers ________________________________________
Der Heap Debugger überwacht (fast) alle vom Programm vorgenommenen Heap-
Operationen und führt unter anderem eine Liste über alle nicht freigege-
benen Heapspeicherbereiche. Der Programmierer, der den Heap Debugger
während der Entwicklungsphase in sein Programm einbindet, wird nach je-
dem Programmabschluß auf übriggebliebene Speicherblöcke hingewiesen.
Der Heap Debugger macht das Auffinden der Fehlerquellen extrem einfach,
weil er (meistens) einen Hinweis auf die Sourcecodestelle (Dateiname und
Zeile) liefert, an der die inkorrekte Heap-Operation vorgenommen wurde
bzw. an der ein später nicht wieder freigegebener Speicherblock allo-
ziert wurde.
Hierzu bedient sich der Heap Debugger der Debug-Informationen für den
externen Debugger, die (optional) an das vom Compiler erzeugte EXE-File
angehängt werden.
___ Was der Heap Debugger kann _________________________________________
Der Heap Debugger überwacht alle Allokationen von Heapspeicher, die mit
den Befehlen
- GetMem
- New
- FreeMem
- Dispose
vorgenommen werden. Auch Aufrufe dieser Routinen aus der Run-Time-
Library und aus Programmteilen heraus, die nicht im Sourcecode vorliegen
(z.B. fremde TPUs), werden berücksichtigt.
Alle nicht korrekt deallokierten Heapspeicherblöcke und sonstige fehler-
hafte Heap-Operationen werden im Heap Debugger Report ausgegeben.
___ Was der Heap Debugger NICHT kann ___________________________________
Folgende Heap-Operationen können vom Heap Debugger NICHT mitverfolgt
werden:
- Mark und Release (dürfen gar nicht verwendet werden !)
- direkte Operationen mit dem globalen Heap (DPMI+Windows),
also alle "Global..."-Aufrufe
- direkte Operationen mit dem lokalen Heap (Windows),
also alle "Local..."-Aufrufe
___ Der Umgang mit dynamischem Speicher ________________________________
In Programme, die intensiv mit Heapspeicher umgehen, schleichen sich
nicht selten heimtückische Programmierfehler ein: Wenn nämlich dynamisch
angeforderte Speicherbereiche nicht korrekt wieder freigegeben werden,
schrumpft der noch verfügbare Heapspeicher nach und nach so weit zu-
Seite 4
sammen, daß irgendwann für eine neue Anforderung nicht mehr genügend
Platz zur Verfügung steht und das Programm abbricht oder -stürzt.
Zum völligen Aufzehren des Heapspeichers kommt es natürlich nur, wenn
Allokationen ohne entsprechende Deallokationen nicht nur einmal, sondern
wiederholt durchgeführt werden. Wenn dieses z.B. mit der Anwahl einer
bestimmten Programmfunktion durch den Benutzer verbunden ist, dann kann
dies vielleicht einige hundert Male gut gehen, bis der übrige Heapspei-
cher aufgebraucht ist. So intensiv werden aber Programme nur selten vom
Programmierer getestet. Also kommen so bedingte Abstürze in der Regel
erst beim Benutzer vor, der dafür natürlich keine Erklärung hat.
Es gibt auch Allokationen, die nur einmalig, also zum Beispiel in der
Initialisierungsphase vorgenommen werden, weil das Programm Speicher-
platz für quasi-statische Variablen benötigt. Solche Variablen (bzw.
Strukturen oder Objekte) könnte der Pogrammierer auch im Datensegment
(als globale Variablen) allokierten, aber da die Größe des Datensegmen-
tes auf insgesamt 64KB beschränkt ist, wird manchmal der Heap als Aus-
weg gewählt. Wenn solche (nur einmalig allokierten) quasi-statischen
Variablen nicht wieder freigegeben werden, so ist dies nur ein Schön-
heitsfehler, hat aber sonst keine Konsequenzen. Der Heap Debugger be-
mängelt aber natürlich auch solche Delikte.
Besonders tückisch sind Deallokationsfehler, d.h. fehlerhafte Freigaben
von Heapspeicher. Ein Deallokationsfehler liegt vor, wenn bei der
Freigabe von Heapspeicher eine falsche Adresse oder eine falsche Länge
angegeben wird, also zu der unternommenen Deallokation zuvor keine pas-
sende Allokation erfolgt ist. Da sich die Runtime-Library weitgehend auf
die Angaben des Programmierers verläßt, können Deallokationsfehler ver-
heerende Folgen haben.
Besonders die Objektorientierte Programmierung macht intensiv von Heap-
speicher Gebrauch. Zu jeder neuen Instanz eines Objektes wird ein Heap-
speicherblock für die Felder des Objektes angefordert, der beim Löschen
der Instanz wieder freigegeben werden muß. Hierzu bedient man sich der
Befehle New und Dispose in der speziell für OOP-Zwecke erweiterten
Syntax. Auch "vergessene" Objekte konsumieren Heapspeicher.
___ Versionen und Zielplattformen ______________________________________
Der Heap Debugger wurde entwickelt und getestet mit
Borland Pascal V7.0 und V7.01
mit den Zielsystemen
- Real Mode (hierfür HDEB7?.TPU)
- Protected Mode (hierfür HDEB7?.TPP)
- Windows (hierfür HDEB7?.TPW)
unter
- DOS 6.2x
- Windows V3.1
- Windows for Workgroups V3.11
- Windows NT 3.5 Workstation
- OS/2 V2.11
Eine Version für Delphi V1.0 für Windows ist in Vorbereitung.
Seite 5
___ Liste der Dateien __________________________________________________
USEHDEB.PAS .... Unit zum Einbinden in Pascalprogramme, für
DOS, DOS/DPMI und WINDOWS
HDEB7S.TPU ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, für DOS/Real Mode
HDEB7S.TPP ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, für DOS/Protected Mode
HDEB7S.TPW ..... Der Kern des Heap Debuggers, nur bei
Sharewareversionen, für Windows
HDEB7F.TPU ..... Der Kern des Heap Debuggers, nur bei
Vollversionen für DOS/Real Mode
HDEB7F.TPP ..... Der Kern des Heap Debuggers, nur bei
Vollversionen für DOS/Protected Mode
HDEB7F.TPW ..... Der Kern des Heap Debuggers, nur bei
Vollversionen für Windows
VIEWME.EXE ..... Der Heap Debugger in Bildern (VGA)
README.TXT ..... Dieser Text (englisch)
LIESMICH.TXT ... Dieser Text (deutsch)
DIZFILES.ZIP ... Für Sysops, nur in Sharewareversionen
SHARWARE.ZIP ... Diese Datei ist nur in Vollversionen
enthalten und enthält die Sharewareversion
BESTELL.TXT .... Bestellformular (deutsch)
ORDER.TXT ...... Bestellformular (englisch)
___ Sharewarekonzept ___________________________________________________
Der Heap Debugger ist Shareware, also KEINE Public Domain oder Freeware!
Die über Sharewarevertriebswege verbeitete Version des Heap Debuggers in
den Dateien HDEB7S.* ("S"=Shareware) und die Begleitdateien und die
Datei USEHDEB.PAS dürfen zu Testzwecken genutzt und an andere weiterge-
geben werden.
Die Sharewareversion ist gegenüber der Vollversion im Leistungsumfang
beschränkt: Die Sharewareversion des Heap Debuggers verfolgt nur die
ersten 50 Allokationen von Heapspeicherblöcken. Alle folgenden Allo-
kationen werden ignoriert. Bei Überschreitung des Sharewarelimits wird
bei Ausgabe des Reports (bei Programmende) eine entsprechende Meldung
ausgegeben.
Registrierte Vollversionen des Heap Debuggers beinhalten die Dateien
HDEB7F.* ("F"=Full). Diese Dateien dürfen NICHT an Dritte weitergegeben
oder ihnen zugänglich gemacht werden.
___ Lizenzbedingungen __________________________________________________
Wer den Heap Debugger in der unbeschränkten Vollversion nutzen möchte,
muß eine Registrierung bei den Autoren vornehmen und erhält im Zuge der
Lieferung der Vollversion eine Lizenz zur Nutzung der Vollversion auf
einem einzelnen Arbeitsplatz.
Bei Nutzung des Heap Debuggers auf mehreren Arbeitsplätzen müssen auch
mehrere Registrierungen bestellt werden. Hierfür bieten wir Staffel-
preise an.
Seite 6
Ein Registrierungsformular ist in der Datei BESTELL.TXT vorbereitet.
Es ist ausdrücklich untersagt, die Vollversion des Heap Debuggers
weiterzugeben. Dies betrifft insbesondere die Dateien HDEB7F.*
___ Nutzungsempfehlungen und Haftungsausschlüsse _______________________
Obwohl wir den Heap Debugger vor der Veröffentlichung ausführlich getes-
tet haben, können wir keine Garantie für einwandfreie Funktion oder Feh-
lerfreiheit dieser Software übernehmen.
Wir empfehlen die Nutzung des Heap Debuggers während der Entwicklungs-
phase. Nach Fertigstellung eines Softwareprodukts sollte unserer Meinung
nach der Heap Debugger nicht mehr eingebunden werden.
Der Heap Debugger soll Ihnen bei der Softwareentwicklung helfen, Fehler
bei der Speicherverwaltung zu vermeiden oder zu beseitigen. Wir weisen
aber auch auf die zusätzlichen Gefahren für die Stabilität einer Soft-
ware, die den Heap Debugger einbindet, hin. Näheres hierzu siehe Ab-
schnitt "Stabilität und Performance".
Bei Lieferungen dieser Software erstreckt sich unsere Garantie aus-
schließlich auf die Lesbarkeit des gelieferten Datenträgers. Wir über-
nehmen keinerlei Haftung für Schäden, die durch Benutzung des Heap
Debuggers eventuell entstehen werden.
ANWENDUNG DES HEAP DEBUGGERS ___________________________________________
___ Den Heap Debugger einbinden ________________________________________
Um den Heap Debugger in ein eigenes Programm einzubinden, müssen Sie nur
die Unit UseHDeb in die Uses-Klausel Ihres Hauptprogramms aufnehmen.
Beispiel:
PROGRAM MyProg;
UseHDeb,
\ /
\/
USES Drivers, Objects, Views, Menus, ...
Es ist sinnvoll, die Unit UseHDeb als erste Unit in der Uses-Klausel
aufzuführen. Die Initialisierung des Heap Debuggers erfolgt über den
Initialisierungsteil dieser Unit. Erst nach der Initialisierung kann der
Heap Debugger Heap-Operationen "beobachten". Deshalb sollte die Initia-
lisierung von UseHDeb möglichst vor der Initialisierung anderer Units,
die eventuell schon Heap-Operationen machen, vorgenommen werden.
Keine der Units, von denen die Units UseHDeb und HDeb7? ihrerseits di-
rekt oder indirekt Gebrauch machen, nimmt in der Initialisierungsphase
Heap-Allokationen vor. Der Heap Debugger erhält also von allen Heap-
Operationen Kenntnis, sofern keine der vom Heap Debugger genutzten Units
modifiziert worden sind.
Seite 7
___ Compiler- und Linkereinstellungen __________________________________
"D+":
Der Heap Debugger wird nur initialisiert, wenn die Unit UseHDeb mit der
Compileroption "D+" (Debug-Informationen ein) übersetzt wird. Das liegt
daran, daß fast die gesamte Unit UseHDeb mit Hilfe der Klausel
{$IFOPT D+}...{$ENDIF} von der Compilierung ausgeschlossen ist, wenn die
Option D+ nicht eingeschaltet ist. Dieser Schalter kann also zum Ein-
und Ausschalten des Heap Debuggers verwendet werden. Theoretisch könnte
der Heap Debugger allerdings auch ohne eingeschaltetes D+ laufen.
Für alle anderen Units, die in Ihr Programm eingebunden werden, sowie
für das Hauptprogramm gilt: Nur wenn mit der Option D+ übersetzt wird,
kann der Heap Debugger in seinem Report Referenzen auf diese Quellda-
teien und Zeilennummern angeben.
"Link-Puffer: Festplatte" und "Externer Debugger":
Damit der Heap Debugger im Report Referenzen auf Quelldateien und Zei-
lennummern liefern kann, müssen die dazu notwendigen Debug-Informa-
tionen in das vom Compiler erzeugte EXE-File (bzw. DLL) geschrieben wer-
den. Neben der Compileroption D+ werden dazu außerdem die Einstellungen
"Link-Puffer: Festplatte" und "Externer Debugger" benötigt. Unter Win-
dows heißt die letzte Option "Debug-Info in EXE".
"Unit-Verzeichnis: \BP\RTL\WIN" (DOS/DPMI und Windows):
Die Unit UseHDeb benötigt im Protected Mode (DOS+Windows) die Unit
WINPROCS. Diese befindet sich gewöhnlich im Verzeichnis "\BP\RTL\WIN".
Da unter DOS dieses Verzeichnis normalerweise nicht als Unit-Verzeichnis
(siehe Option-->Verzeichnisse) eingestellt ist, müssen Sie dieses Ver-
zeichnis selbst in der Liste der Unit-Verzeichnisse ergänzen.
___ Wenn die Initialisierung fehlschlägt _______________________________
Die Initialisierung des Heap Debuggers wird von dem Initialisierungteil
der Unit UseHDeb vorgenommen. Bei Fehlschlagen der Initialisierung gibt
UseHDeb die Meldung "Heap Debugger konnte nicht initialisiert werden !"
aus und stoppt das Programm mit dem Kommando HALT.
Das Fehlschlagen der Initialisierung kann folgende Ursachen haben:
- Sie verwenden eine modifizierte Run-Time-Library, die in
einem für den Heap Debugger wichtigen Punkt nicht mit dem
Original von Borland übereinstimmt.
- Sie verwenden ein von uns nicht getestetes Betriebssystem
oder spezielle, von uns nicht getestete Tools (z.B. zur
Speicherverwaltung).
- Sie verwenden eine von uns nicht getestete Compilerversion.
- Es wurden keine freien Interruptvektoren gefunden. Der
Heap Debugger benötigt drei freie Interrupts. In diesem
Falle ist wahrscheinlich unsere Testmethode zum Finden
freier Interrupts verantwortlich. Es kommt selten vor,
daß tatsächlich alle Interrupts belegt sind.
- Der Heap Debugger ist schon initilisiert. Dies sollte bei
Verwendung der Unit UseHDeb nicht vorkommen.
Seite 8
Wenn bei Ihrem System die Initialisierung des Heap Debuggers fehlschla-
gen sollte, dann versuchen Sie bitte zunächst, Ihr Programm in einer von
uns getesteten Konfiguration (z.B. MSDOS 6.2, ggf. Windows 3.1) ohne
vorheriges Laden irgendwelcher spezieller Speichermanager oder Multi-
tasker zu laden. Beobachten Sie, ob der Heap Debugger in dieser Konfi-
guration initialisiert werden kann.
Bitte informieren Sie uns über Konfigurationen, in denen der Heap
Debugger nicht betrieben werden kann (möglichst per email).
___ Der Heap Debugger Report ___________________________________________
Der Heap Debugger gibt beim Beenden des untersuchten Programms einen Re-
port aus. Dies geschieht in der Exit-Prozedur der Unit UseHDeb.
Der Heap Debugger Report hat in der Regel folgenden Aufbau (Beispiel):
HEAP DEBUGGER DIAGNOSE:
2 Pointer wurden registiert (*1)
1 Debug-Eintraege vorhanden (*2)
auflisten (J/N) ? j
(*3) (*4) (*5) (*6) (*7) |------(*8)------|
Nr Pointer Size Flags Aufrufer Datei Zeile
2 1A41:0000 256 0000[122D]:0044 HEAPBUG.PAS 16
(*1): Hier wird angegeben, wieviele Heap-Allokationen der Heap Debugger
insgesamt mitverfolgt hat. Diese Zahl enthält also noch keine
Aussage über eventuelle Fehler.
(*2): Hier wird angegeben, wieviele Diagnosezeilen der Heap Debugger
auszugeben hat. Im Idealfall sollte hier immer "0" stehen. Nicht
alle, aber die meisten Diagnosezeilen deuten auf einen Program-
mierfehler hin.
(*3): Hier wird eine laufende Nummer aller vom Programm vorgenommener
Allokationen ausgegeben. Bei Deallokationen (Flag "F") steht hier
nichts.
(*4): Hier wird die Adresse des allokierten bzw. deallokierten
Heapspeicherblocks ausgegeben. Diese Adresse kann von Programmlauf
zu Programmlauf variieren.
(*5): Hier wird die Größe des allokierten bzw. deallokieren Blocks
ausgegeben.
(*6): Die hier ausgegebenen Flags haben folgende Bedeutung
(Kombinationen sind möglich):
keins: Es handelt sich um eine Allokation, zu der keine passende
Deallokation erfolgt ist.
"O" : Es handelt sich um die Daten einer Objektinstanz. Das ist
der Datenbereich, der vom Constructor eines Objektes
für die Felder des Objektes (und anderes) bei jeder neuen
Instanz angelegt wird. Als Aufrufer wird die Zeile mit
dem Word "BEGIN" des Construktors angegeben, bzw. die Zeile
mit dem Word "END" des Destructors bei Deallokationen.
"F" : Bei dieser Diagnosezeile geht es um eine Deallokation
(F=free). Was bei dieser Deallokation schiefgegangen ist,
wird mit einem der folgenden Flags angegeben.
Seite 9
"S" : Ein Heapspeicherblock wurde nicht mit der gleichen Block-
länge (S=size) deallokiert, mit der er allokiert wurde. In
diesem Falle wird dieses Flag sowohl in der Diagnosezeile
der Allokation als auch in der der Deallokation ausgegeben.
"M" : Zu einer Deallokation wurde keine passende Allokation
gefunden (M=mismatch). Das heißt, daß versucht wurde, einen
Heapspeicherblock zu deallokieren, dessen Adresse nicht bei
einer vorangegangenen Allokation registriert worden ist.
Dieses Flag tritt nur zusammen mit dem Flag "F" auf.
(*7): Hier wird die Adresse der aufrufenden Programmstelle ausgegeben.
An dieser Programmstelle wurde die in der Diagnosezeile angegebene
Heap-Operation aufgerufen. Die Segmentadresse dieser Stelle ist
sowohl als virtuelle Segmentadresse (in eckigen Klammern "[]")
als auch aktuelle Segmentadresse angegeben. Die virtuelle Segment-
adresse wird vom Linker vergeben und ist die Adresse relativ zur
Adresse 0000. Die aktuelle Adresse wird beim Laden des Programms
vergeben und ist abhängig von der Stelle, an die das Programm in
den Speicher geladen wird. Die virtuelle Adresse findet sich im
MAP-File des Programms wieder. Die aktuelle Adresse kann von Pro-
grammlauf zu Programmlauf variieren.
(*8): Hier wird die Sourcecodestelle (Dateiname und Zeilennummer) ange-
geben, die sich die Aufrufer-Adresse bezieht. Voraussetzung dafür
ist, daß überhaupt Debug-Informationen im EXE-File existieren.
Sind keine Debug-Informationen vorhanden, dann wird hier
"keine Info." angezeigt. Wenn zwar Debug-Informationen vorhanden
sind, aber die Sourcecodestelle zu der Aufrufer-Adresse trotzdem
nicht gefunden werden konnte, dann wird hier "?" angezeigt.
___ Besondere Meldungen im Heap Debugger Report ________________________
Folgende Meldungen können im Heap Debugger Report in Ausnahmefällen auf-
treten:
"Programm durch HALT(nnn) gestoppt"
Diese Meldung erscheint, wenn das Programm gezielt mit dem Befehl
HALT(nnn) gestoppt wurde. Der Exitcode wird mit nnn angegeben.
"Laufzeitfehler nnn bei ssss:oooo, Datei: ________ Zeile: _____"
Wenn das Programm durch einen Laufzeitfehler abgebrochen wird, erscheint
diese Meldung. Als zusätzliche, nützliche Information wird die
Programmstelle des Laufzeitfehlers (Quelldateiname und Zeilennummer)
ausgegeben, sofern diese Information verfügbar ist.
"interner Fehler 203 im Heap Debugger aufgetreten"
Diese Meldung bedeutet, daß dem Heap Debugger zur Laufzeit nicht genü-
gend Heapspeicher zur Verfügung stand, um alle Heap-Operationen auf-
zeichnen zu können.
"Shareware-Limit ueberschritten!
Es wurden nur 50 pointer verarbeitet!"
Diese Meldung wird nur von der Sharewareversion ausgegeben und besagt,
daß das Sharewarelimit von 50 überwachten Allokationen zur Laufzeit
überschritten worden ist.
Seite 10
___ Interpretation des Reports _________________________________________
Natürlich sollte man immer anstreben, am Ende eines Programmlaufs vom
Heap Debugger die Meldung "0 Debug-Eintraege vorhanden" gemacht zu
bekommen. Wenn der Heap Debugger während der gesamten Entwicklungszeit
einer Applikation kontinuierlich eingesetzt wird, dann läßt sich eine
nach einem Testlauf plötzlich auftauchende andere Meldung meist sehr
leicht mit der zuletzt vorgenommenen Programmänderung in Zusammenhang
bringen.
Wenn die Sache einmal nicht so einfach ist, muß man die Diagnose des
Heap Debuggers zunächst einmal interpretieren, um dem Problem auf die
Schliche zu kommen.
Hierzu sollte man sich die folgenden Fragen stellen:
- Ist die Anzahl der Diagnoseeinträge immer gleich oder variiert diese
Anzahl ?
Soweit die Anzahl nicht variiert, handelt es sich offenbar um
einmalig vorkommende Fehler im Programm. Es gibt Fälle, bei denen
die Bezeichnung Fehler sogar etwas zu scharf gewählt ist. Manche
Programme legen nämlich quasi-statische Variablen auf dem Heap an,
und geben diese dann am Ende nicht wieder frei. So ein Verhalten
ist zwar nicht sonderlich schön und sollte deshalb vermieden werden;
es hat andererseits aber auch keine schlimmen Konsequenzen.
- Läßt sich das Anwachsen der Anzahl der Diagnosezeilen mit einer
bestimmten Funktion meines Programms in Zusammenhang bringen ?
Wenn die Anzahl wächst, dann sollte man versuchen, den sich
offenbar wiederholenden Fehler auszumachen. Meistens ist das sehr
einfach, wenn nämlich der Heap Debugger für mehrere Einträge die
selbe Aufruferadresse ausgibt. Es handelt sich dann wohl um einen
Fehler, der immer dann zum Tragen kommt, wenn eine bestimmte
Programmfunktion ausgelöst wird. Solche Fehler sollte man auf jeden
Fall beseitigen, da sie den gefürchteten "Gedächtnisschwund" auslösen.
- Wurde in einzelnen Diagnosezeilen irgendein Flag eingetragen ?
Soweit nicht, handelt es sich bei den Diagnosen des Heap
Debuggers um Hinweise auf "klassische" Fehler, nämlich auf das
unterlassene Freigeben "normaler" Heapspeicherblöcke, die
mittels GetMem oder New angefordert wurden. Die Sourcecodereferenz
verweist auf die Stelle, an der diese Anforderung geschehen ist.
- Wurde in einzelnen Diagnosezeilen das Flag "O" eingetragen ?
Soweit ja, weist der Heap Debugger auf Verfehlungen im Zusammenhang
mit Objekten hin. Wird z.B. nur ein "O" eingetragen, dann handelt
es sich um nicht freigegebene Instanzdaten eines Objektes, welche
(im allgemeinen) mittels New in der OOP-Variante, nämlich
New(ptr, constructor), angelegt worden sind. Die Sourcecodereferenz
deutet aber dann NICHT auf diese New-Anweisung, sondern auf die
Zeile BEGIN im betreffenden Constructor. Wenn man diesen ausgemacht
hat, muß man überlegen, wo Instanzen dieses Objekttyps angelegt
werden und dort auf korrekte Freigaben prüfen.
Seite 11
- Wurde in einzelnen Diagnosezeilen das Flag "F" eingetragen ?
Dieses Flag kommt nie allein. Es bedeutet (meistens), daß ein Deallo-
kationsfehler passiert ist. Außer dem "F" ist immer entweder ein
"S" oder ein "M" gesetzt, was bedeutet, daß entweder eine Deallokation
mit einer falschen Blocklänge aufgerufen worden ist, bzw. daß der
deallokierte Speicherblock an einer Adresse liegt, an der vorher
keine Allokation vorgenommen worden ist.
Solche Diagnosen sind entweder sehr schlimm oder sehr harmlos.
Der harmlose Fall ist im Abschnitt "MemAllocSeg" beschrieben. Wenn
diese Beschreibung nicht zutrifft, dann liegt wahrscheinlich ein
echter Fehler vor, der unbedingt gefunden werden muß, weil er das
gesamte Programm (auch den Heap Debugger) zum Absturz bringen kann.
Letzteres kann passieren, wenn die Konsistenz der Heapverwaltung
nicht mehr gegeben ist. In so einem Fall können übrigens auch Daten
auf dem Heap verstümmelt werden.
___ Auffinden von Bugs _________________________________________________
Wenn der Heap Debugger zu seinen Diagnosen Sourcecodereferenzen ausgeben
konnte, dann ist das Auffinden von Bugs verhältnismäßig einfach.
Wenn die Sourcecodereferenz allerdings mit "?" angegeben wird, dann be-
findet sich die unter "Aufrufer" aufgeführte Adresse in einem Modul, das
nicht mit der Option "D+", also ohne Debuginformationen übersetzt worden
ist. Oft ist der Aufrufer dann in der Run-Time-Library zu finden.
Man sollte sich aber nicht zu dem Schluß verleiten lassen, daß man für
den entsprechenden Fehler dann gar nicht verantwortlich ist und daß die
Run-Time-Library einen Bug hat. Wenn von Ihnen z.B. eine Allokation
mittels "NewStr" (Funktion der Run-Time-Library) vorgenommen wurde,
und der so angeforderte Heapspeicherblock wurde anschließend nicht
korrekt mit DisposeStr deallokiert, dann liegt der Fehler in Ihrem
Programmteil; als Aufrufer wird aber eine Zeile in der Funktion NewStr
genannt.
Viele Probleme dieser Art kann man lösen, indem man die ganze
Run-Time-Library mit Debug-Option neu übersetzt. Das ist nur bei
BP7.0, nicht bei TP7.0 möglich. Informationen hierzu bietet Borland
in der Datei \BP\RTL\README.
___ Arbeiten mit einem externen Debugger _______________________________
In hartnäckigen Fällen kann man versuchen, einen Fehler mit Hilfe des
externen Debuggers einzugrenzen. Das ist besonders dann sinnvoll, wenn
man dem Heap Debugger trotz aller Bemühungen keine Sourcecodereferenz
entlocken kann.
Im externen Debugger sollte man versuchen, auf die fragliche Programm-
stelle (die Aufruferadresse) einen Breakpoint zu setzen.
Beachten Sie hierzu den Unterschied zwischen der virtuellen und der
aktuellen Segmentadresse, die der Heap Debugger ausgibt.
Seite 12
Achtung: Die aktuelle Segmentadresse eines Aufrufers kann sich von
Programmlauf zu Programmlauf verschieben. Nach dem Laden des Debuggers
wird sie sich sogar sehr wahrscheindlich verschieben. Lassen Sie daher
Ihr Programm mit geladenem Debugger einmal oder mehrmals laufen, ohne
einen Breakpoint zu setzen. Verwenden sie die zuletzt ausgegebene
aktuelle Segmentadresse, um den Breakpoint zu setzen. Sie setzen einen
Breakpoint auf eine von Hand eingegebene Adresse mit der Funktion
"Breakpoints->At...". Geben Sie einfach die Adresse ein und beginnen Sie
die Segmentadresse UND die Offsetadresse jeweils mit "$" für hexadezi-
male Notation.
Wenn Sie Ihr Programm dann starten und einen Breakpoint erreichen,
versuchen Sie das Programm ab dieser Stelle in Einzelschritten fortzu-
setzen, bis Sie zu einer Stelle des Programms kommen, die Ihnen bekannt
ist.
___ Compilerschalter in USEHDEB ________________________________________
In die Unit UseHDeb wurden bereits einige Compilerschalter eingeführt,
die die Anpassung an besondere Anforderungen erleichtern sollen. Wir
hoffen, daß damit die allermeisten Anpassungsprobleme zu lösen sind, so
daß dem Anwender eine weitergehende Veränderung des Sourcecodes erspart
bleibt.
Der Schalter "USE_SHAREWARE":
Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger in einer der
Units "HDEB7S.TP?" benutzt. Wenn er ausgeschaltet ist, dann wird eine
der Units "HDEB7F.TP?" eingebunden. Letztere stellt die Vollversion des
Heap Debuggers dar und kann natürlich nur verwendet werden, wenn die
Software registriert worden ist. Dieser Compiler ist bei Lieferung der
Shareware- bzw. der Vollversion schon richtig eingestellt und muß also
in der Regel nicht verändert werden.
Der Schalter "GERMAN_LANG":
Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger Report in
deutscher Sprache ausgegeben, sonst in Englisch.
Der Schalter "GETDEBUGINFO":
Wenn dieser Schalter aktiv ist, dann wird bei der Reportausgabe ver-
sucht, auf die Debug-Informationen im EXE-File zuzugreifen, um Dateina-
men und Zeilennummer zu jeder Diagnosezeile zu ermitteln. Dieser Schal-
ter sollte normalerweise aktiv bleiben.
Der Schalter "REPORT_TO_FILE":
Wenn dieser Schalter aktiv ist, dann wird die Reportausgabe der Unit
UseHDeb in eine Datei umgeleitet. Der Name dieser Datei wird mit der
Konstanten DumpFileName festgelegt und ist auf "HEAPDEB.DMP" voreinge-
stellt, kann aber verändert werden. Die Datei wird mit jeder Reportaus-
gabe erweitert. Bitte beachten Sie: Wenn der Heap Debugger aus irgendei-
nem Grund nicht initialisiert wurde und der Schalter "REPORT_TO_FILE"
aktiviert ist, dann wird das Programm ohne Ausgabe einer Meldung (auch
nicht in die Datei) mit dem Kommando "HALT" gestoppt.
Seite 13
Der Schalter "SWITCH_TO_LASTMODE":
Wenn dieser Schalter aktiv ist, dann wird vor der Reportausgabe der Unit
UseHDeb mit dem Kommando "Textmode(LastMode)" in den Videomodus zurück-
geschaltet, der beim Start des Programms aktiv war. Dies kann nützlich
sein, wenn das Hauptprogramm z.B. in einen vom BIOS nicht unterstützten
Grafikmodus umschaltet oder Textfarben so manipuliert, daß die Report-
ausgabe nicht lesbar ist. Dieser Schalter hat unter Windows keine Aus-
wirkung.
Beispiel für das Ein- und Ausschalten eines Schalters:
aktiv: "{$DEFINE GERMAN_LANG}"
inaktiv: "{not $DEFINE GERMAN_LANG}"
HEAP DEBUGGING IM DETAIL _______________________________________________
___ Overlays ___________________________________________________________
Sie können den Heap Debugger auch innerhalb von Programmen nutzen, die
von Overlayprogrammierung Gebrauch machen. Die Units USEHDEB und HDEB7?
dürfen allerdings nicht als Overlays geladen werden.
___ DLLs _______________________________________________________________
Eine DLL kann man mit dem Heap Debugger behandeln wie ein normales, ei-
genständiges Programm. Wenn ein Programm, das den Heap Debugger verwen-
det, zur Laufzeit eine DLL einbindet, dann ist der Heap Debugger für
diese DLL nicht wirksam. Umgekehrt kann eine DLL den Heap Debugger ver-
wenden, ohne daß dadurch die Heap-Operationen im Hauptprogramm überwacht
werden. Wird sowohl in eine DLL alsauch in das Hauptprogramm der Heap
Debugger eingebunden, so werden zum Programmende zwei Reporte ausgege-
ben.
Das Einbinden des Heap Debuggers in eine DLL erfolgt demgemäß auch wie
bei einem normalen Programm: In der Hauptquelldatei der DLL (mit der
Überschrift "library") wird die Unit UseHDeb als erste in die uses-
Klausel eingefügt.
Der Exit-Code der Unit UseHDeb (mit der Reportausgabe) wird beim Beenden
der DLL durchgeführt. Wann ist das ? Die DLL wird normalerweise beendet,
wenn auch das Hauptprogramm, das die DLL geladen hat, beendet wird. Es
gibt allerdings Ausnahmen. Wenn man das Hauptprogramm mit dem externen
Debugger ausführt, so wird die DLL nicht bei Programmende abgeschlossen,
sondern beim Verlassen des Debuggers, was dann aus unerfindlichen Grün-
den häufig zu einem Absturz des Rechners führt. Es empfiehlt sich daher
sehr, eine DLL, die den Heap Debugger einbindet, zur Laufzeit des Haupt-
programms gezielt mit der Anweisung "FreeLibrary" zu beenden, wodurch
der Exit-Code der Unit UseHDeb für die DLL ausgeführt und somit der Re-
port ausgegeben wird.
Das bisher Gesagte gilt für DLLs unter DOS und unter Windows gleicher-
maßen.
Seite 14
Unter Windows ergibt sich aber noch ein zusätzliches Problem: Die Re-
portausgabe, die von der Unit UseHDeb unter Windows ja in ein WinCrt-
Fenster vorgenommen wird, klappt bei einer DLL nicht: Die Folge des Ver-
suches, eine Reportausgabe aus einer DLL heraus in ein WinCrt-Fenster
vorzunehmen, ist in aller Regel entweder ein Laufzeitfehler oder das
völlige Ausbleiben jeder Ausgabe. Unter DOS gibt es diese Probleme
nicht.
Es ist unter Windows bei Einsatz des Heap Debuggers in einer DLL also
unbedingt notwendig, die Ausgaben der Unit UseHDeb in eine Datei umzu-
leiten. Hierfür wurde der Schalter "REPORT_TO_FILE" vorbereitet (siehe
hierzu "Compilerschalter in USEHDEB").
___ Programminstanzen (Windows) ________________________________________
Wenn unter Windows ein Programm, das den Heap Debugger einbindet, in
mehreren Instanzen gestartet wird, so wird nur für die erste Instanz der
Heap Debugger installiert. Folgende Instanzen nutzen automatisch den
schon installierten Heap Debugger mit. Die Ausgabe des Reports erfolgt
erst nach Beenden der letzten aktiven Instanz des Programms, und der Re-
port beinhaltet alle Heap-Operationen, die in anderen Instanzen des sel-
ben Programms vorgenommen wurden, ohne das die verursachenden Instanzen
in dem Report voneinander unterschieden werden können. Um die Übersicht-
lichkeit zu wahren, sollten also möglichst nicht mehrere Instanzen aus-
geführt werden.
___ Interrupts ________________________________________________________
Der Heap Debugger benötigt für seine Arbeit drei eigene Softwareinter-
rupts. Das heißt, daß der Heap Debugger bei der Installation drei freie
Interruptvektoren belegt und diese bei Programmende wieder restauriert.
Der Heap Debugger sucht sich die freien Softwareinterrupts selbst aus,
und zwar im Bereich 78h bis FFh. Aus diesem Bereich können gezielt ein-
zelne Interrupts vom Programmierer ausgeschlossen werden, indem in der
Unit UseHDeb.PAS die Anweisung "HeapDebInit([])" verändert wird. In der
als Parameter angegebenen leeren Menge kann eine Menge von Interruptnum-
mern definiert werden, die vom Heap Debugger nicht benutzt werden
sollen. Eine Änderung dieses Aufrufes in "HeapDebInit([$F0..$FF])" würde
z.B. die Interruptvektoren F0h bis FFh für die Benutzung durch den Heap
Debugger ausschließen und somit für das Hauptprogramm freihalten.
___ Stabilität und Performance _________________________________________
Wie schon erläutert sollte der Heap Debugger nicht als Bestandteil fer-
tiger Applikationen eingesetzt werden. Der Heap Debugger sollte aus-
schließlich als Debuggingwerkzeug in der Entwicklungsphase verwendet
werden.
Der permanente Einsatz des Heap Debuggers während der Softwareentwick-
lung kann die Stabilität der entwickelten Software erheblich verbessern
und die Entwicklungszeit verkürzen.
Es ist jedoch nicht auszuschließen, daß der Heap Debugger in der Ent-
wicklungsphase eine potentielle Ursache für Programmabstürze sein kann,
auch wenn dies von uns bisher nicht beobachtet werden konnte. Folgende
Tatsachen sollten beachtet werden:
Seite 15
- Der Heap Debugger überwacht nicht nur die korrekte Verwendung des
Heapspeichers. Er benötigt auch selbst Heapspeicher für diese Aufgabe.
Wenn ein Programm zeitweise eine große Anzahl von Heapspeicherblöcken
allokiert, so kann der zusätzliche Speicherbedarf des Heap Debuggers
erheblich sein. Mit zusätzlichen 24 Byte je allokiertem (und noch
nicht wieder deallokiertem) Speicherblock sollte gerechnet werden.
- Die Ausführung des Heap Debuggers erfordert zusätzlich Platz auf dem
Stack, und zwar sowohl bei der Ausführung von Speicheroperationen als-
auch bei der Ausgabe der Reports in der Exitprozedur der Unit UseHDeb.
Hier ist zu beachten, daß teilweise keine Überprüfung des Stacks mög-
lich ist, so daß ein zu klein dimensionierter Stack ein Programm zum
Absturz bringen kann.
- Bei massiven Fehlern des Applikationsprogrammierers bei dem Umgang mit
Heapspeicher kann der Einsatz des Heap Debuggers, der wie gesagt auch
selbst mit Heapspeicher arbeitet, den Absturz eines Programmes sogar
erst auslösen, was, in einer zufällig anderen Konstellation, ohne den
Heap Debugger vielleicht nicht passiert wäre. Solche Abstürze können
zum Beispiel dann passieren, wenn die Applikation versucht, einen vor-
her gar nicht allokierten Speicherbereich freizugeben. In diesem Fall
ist ein Programmabsturz als klares Indiz für einen Programmierfehler
jedenfalls einem trügerischen fehlerfreien Programmablauf vorzuziehen.
- Der Heap Debugger braucht für seine Arbeit zusätzliche Rechenzeit. Je
mehr Speicherblöcke allokiert werden, um so mehr steigt der Zeitbedarf
des Heap Debuggers, insbesondere beim Wiederfreigeben von Speicher.
Diese Performanceeinbuße wird aber allenfalls bei sehr zeitkritischen
Anwendungen irgendwie spürbar sein.
- Der Heap Debugger benötigt, wie schon im vorherigen Abschnitt erwähnt,
für seine Arbeit drei freie Softwareinterrupts, deren Vektoren er zum
Anfang des Programms auf eigene Routinen umlenkt und zum Ende des Pro-
gramms wieder restauriert. Wenn ein Programm durch einen fatalen Feh-
ler so abrupt beendet wird, daß die Exitprozedur von UseHDeb nicht
mehr durchlaufen wird, dann werden auch diese Interruptvektoren nicht
mehr wieder auf ihre alten Werte eingestellt. Wenn anschließend gela-
dene Programme aber von korrekten Werten in diesen Vektoren abhängig
sind, so kann dies zu Problemen führen. Wenn sich solche Abstürze sehr
häufig wiederholen, dann kann der Heap Debugger irgendwann keine
freien Interrupts mehr finden und kann nicht gestartet werden.
___ Eingriffsmöglichkeiten für den Programmierer _______________________
Es ist für einige Fälle denkbar, daß ein Programmierer Änderungen am
Heap Debugger vornehmen möchte, um z.B. die Reportausgabe seinen eigenen
Vorstellungen anzupassen. Aus diesem Grunde wird die Unit UseHDeb im
Quellcode mitgeliefert. Programmänderungen dürfen nur an dieser Unit und
nur zu eigenen, nichtkommerziellen Zwecken vorgenommen werden.
Darüberhinaus bietet das Interface der Unit HDeb7?.TP? folgende typi-
sierte Konstanten an, die zur Laufzeit eines Programms verändert werden
können:
Seite 16
1) SuspendHeapdeb : Boolean = false;
Wird diese Konstante zur Laufzeit des Hauptprogramms auf TRUE gesetzt,
so werden anschließend keine Heap Operationen vom Heap Debugger mehr
aufgezeichnet. Nach Rückänderung des Wertes auf FALSE arbeitet der Heap
Debugger wieder normal. Dies kann z.B. nützlich sein, um quasi statische
Allokationen, die sonst bei jeder Reportausgabe des Heap Debuggers auf-
geführt werden, für den Heap Debugger "unsichtbar" zu machen und dadurch
einen "sauberen" Report zu ermöglichen.
2) RecordZeroSize : Boolean = false;
Solange diese Konstante den Wert FALSE hat, werden Allokationen und De-
allokationen mit der Länge Null vom Heap Debugger ignoriert. Weil solche
Operationen reine Schönheitsfehler sind und unseres Wissens keinen Scha-
den anrichten können, ist diese Konstante auf FALSE voreingestellt.
3) RTEOnWrongSizedFree : Byte = 0;
Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
wird bei jeder Deallokation, die nicht die gleiche Länge wie die zuge-
hörige Allokation aufweist (Flag "S"), sofort ein Run-Time-Error ausge-
löst. Die Nummer des Run-Time-Errors wird durch diese Konstante
bestimmt.
4) RTEOnUnknownFree : Byte = 0;
Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
wird bei jeder Deallokation, zu der keine passende Allokation (gleiche
Anfangsadresse des Heapspeicherblocks) gefunden werden kann (Flag "M"),
sofort ein Run-Time-Error ausgelöst. Die Nummer des Run-Time-Errors wird
durch diese Konstante bestimmt.
BEKANNTE EINSCHRÄNKUNGEN UND PROBLEME __________________________________
___ Mark/Release _______________________________________________________
Von der Verwendung der Befehle Mark und Release erhält der Heap Debugger
keinerlei Kenntnis und kann sie also auch nicht berücksichtigen. Darüber
hinaus kann die Anweisung Release den Heap Debugger erheblich stören
(bis hin zum Programmabsturz), weil dadurch eventuell auch Aufzeichnun-
gen des Heap Debuggers verworfen werden, ohne daß der Heap Debugger die-
ses erkennen kann.
Allerdings werden die Befehle Mark und Release fast gar nicht mehr ver-
wendet, denn sie bringen, unabhängig von der Unverträglichkeit mit dem
Heap Debugger, noch eine Reihe anderer Probleme mit sich. Wahrscheinlich
sind sie in der aktuellen Version des Compilers nur noch aus Kompatibi-
litätsgründen implementiert. Von der Verwendung von Mark und Release ist
also allgemein abzuraten. Mark und Release stehen nur unter DOS zur Ver-
fügung.
Seite 17
___ MemAllocSeg ________________________________________________________
Die Funktion MemAllocSeg in der Unit Memory (unter Windows: OMemory)
stellt den Heap Debugger vor ein großes Problem: Die Aufgabe dieser
Funktion ist es, einen Heapspeicherbereich anzufordern, dessen Anfangs-
adresse genau auf dem Anfang eines Speichersegmentes liegt, also die
Offsetadresse 0000 hat. Um dieses zu erreichen, greift die Funktion
MemAllocSeg tief in die Trickkiste, wobei wir zwischen den verschiedenen
Zielplattformen unterscheiden müssen:
Real Mode:
Um garantiert einen Heapspeicherbereich mit der Offsetadresse 0000 allo-
kieren zu können, reserviert die Funktion MemAllocSeg mittels GetMem zu-
nächst einen etwas größeren Bereich, um anschließend sofort wieder einen
kleinen Teil davon (nämlich 8 Bytes), die entweder am Anfang oder am
Ende des gerade allokierten größeren Bereichs liegen, mittels FreeMem
freizugeben. Hier wird also etwas getan, was zwar in engen Grenzen er-
laubt, aber verpönt ist: Der Heap Debugger "beobachtet" diese Operatio-
nen und wird sie später in seinem Report ausgeben. Das kann dann z.B. so
aussehen:
program TEST;
uses UseHDeb, Memory;
var p: pointer;
begin
{...}
p := MemAllocSeg(100);
FreeMem(p, 100);
end.
HEAP-DEBUGGER-DIAGNOSE:
1 Pointer wurden registiert
3 Debug-Eintraege vorhanden
auflisten (J/N) ? j
Nr Pointer Size Flags Aufrufer Datei Zeile
1 1A4D:0000 112 S 020B[1438]:001F MEMORY.PAS 327
1A53:0008 8 F M 020B[1438]:00D5 MEMORY.PAS 355
1A4D:0000 100 FS 0000[122D]:003A TEST.PAS 7
Oder so:
HEAP-DEBUGGER-DIAGNOSE:
1 Pointer wurden registiert
3 Debug-Eintraege vorhanden
auflisten (J/N) ? j
Nr Pointer Size Flags Aufrufer Datei Zeile
1 1531:0008 112 S 020C[0F1A]:001F MEMORY.PAS 327
1531:0008 8 FS 020C[0F1A]:00D5 MEMORY.PAS 355
1532:0000 100 F M 0000[0D0E]:004A TEST.PAS 7
Der Programmierer ist wohl oder übel gezwungen, solche nicht ganz ast-
reinen Heap-Operationen zu dulden und derartige Diagnosen des Heap
Debuggers zu ignorieren.
Seite 18
(Die Referenz auf die Sourcecodestellen in der Unit Memory werden nur
dann ausgegeben, wenn diese Unit mit der Option $D+ übersetzt worden
ist.)
Protected Mode (DOS/DPMI):
Hier hat es die Funktion MemAllocSeg etwas einfacher als im Real Mode:
Sie ruft einfach die Funktion "MemAllocateBlock" auf, welche von der
RTM.EXE zur Verfügung gestellt wird und eine entsprechene DPMI-Funktion
darstellt. Dadurch wird ein Heapspeicherblock allokiert, der garantiert
bei der Offsetadresse 0000 beginnt. Wie schon im Abschnitt "Globaler und
lokaler Heap" beschrieben, erhält der Heap Debugger von diesem Vorgang
keine Kenntnis. Die Freigabe des so allokierten Heapspeicherblocks wird
jedoch überlicherweise mit der Funktion FreeMem vorgenommen, wovon der
Heap Debugger sehr wohl Kenntnis erhält. Das oben gezeigte TestProgramm
würde also im Protected Mode folgende Reportausgabe hervorrufen:
HEAP-DEBUGGER-DIAGNOSE:
0 Pointer wurden registiert
1 Debug-Eintraege vorhanden
auflisten (J/N) ? j
Nr Pointer Size Flags Aufrufer Datei Zeile
059F:0000 100 F M 0001[0547]:003D TEST.PAS 7
Windows:
Hier gilt das gleiche wie im Protected Mode unter DOS, nur daß sich die
Funktion MemAllocSeg der Funktion "GlobalAlloc" bedient, um einen Heap-
speicherbereich mit der Offsetadresse 0000 zu allokieren. Da es sich
hier um eine Operation mit dem globalen Heap handelt, merkt der Heap
Debugger davon nichts. Die Freigabe dieses Heapspeicherbereichs mittels
FreeMem wird aber registiert. Die Konsequenz für den Heap Debugger ist
die gleiche wie im Protected Mode unter DOS.
___ BGI ________________________________________________________________
Bei der Initialisierung von BGI-Treibern tritt mitunter das bei
"MemAllocSeg" beschriebene Problem auf. Vermutlich verwenden BGI-Treiber
oder die Unit Graph eine eigene Implementation der Funktion
"MemAllocSeg".
___ TMemoryStream ______________________________________________________
Dieser Stream benutzt in der Methode "ChangeListSize" die Funktion
"MemAllocSeg", die weiter oben beschrieben ist.
___ Heapüberlauf _______________________________________________________
Der Heap Debugger, der ja die Heap-Operationen eines Programms überwa-
chen soll, benötigt für seine Arbeit selbst ebenfalls Heapspeicher.
Falls der Heap Debugger selbst keinen Heapspeicher mehr anfordern kann,
weil dieser aufgebraucht ist, so wird bei der Reportausgabe ein Interner
Fehler Nummer 203 gemeldet. Wenn das Hauptprogramm eine HeapError-Funk-
tion definiert hat, dann kommt diese auch beim Scheitern einer Heapallo-
kation innerhalb des Heap Debuggers zur Ausführung.
Seite 19
___ Programmabbruch ____________________________________________________
Wird ein Programm, das den Heap Debugger einbindet, abgebrochen, ohne
daß die Exit-Prozedur der Unit UseHDeb (die den Report ausgibt) durch-
laufen wird, so werden die von vom Heap Debugger veränderten Software-
interrupts nicht restauriert und stehen danach - zumindest für den Heap
Debugger - nicht mehr als freie Interruptvektoren zur Verfügung. Nicht
restaurierte Interruptvektoren, die sonst nirgens verwendet werden,
stellen eigentlich kaum eine Gefahr dar, da diese Interrupts eigentlich
von keinem Programm aufgerufen werden. Beim Neuinitialisieren des Heap
Debuggers bei einem neuerlichen Programmstart werden aber wieder drei
andere Interruptvektoren ausgesucht. Wenn sich die "harten" Abstürze
wiederholen (ca. 40 mal), stehen irgendwann keine freien Interruptvekto-
ren mehr zur Verfügung und der Heap Debugger kann nicht mehr initiali-
siert werden, was sich nur durch einen Neustart des Rechners beheben
läßt.
___ WINCRT _____________________________________________________________
Wenn das Hauptprogramm schon ein WinCrt-Fenster benutzt und dieses nicht
mit DoneWinCrt geschlossen wird, bevor die Exit-Prozedur der Unit
UseHDeb durchlaufen wird, dann bleiben typischerwiese 2000 Byte Heap-
speicher allokiert, die dann im Heap Debugger Report aufgeführt werden.
Man sollte deswegen aber im Hauptprogramm kein DoneWinCrt-Kommando pro-
grammieren, denn dies führt oft bei der Reportausgabe des Heap Debuggers
zu neuen Problemen.
Wie schon im Abschnitt "DLLs" beschrieben, kann der Heap Debugger bei
der Einbindung in eine DLL keine Ausgabe in ein WinCrt-Fenster machen.
In allen Zweifelsfällen sollte man versuchen, auf die Möglichkeit der
Reportausgabe in eine Datei auszuweichen.